#include "parse_tree_def.h"
#include <ctype.h>
#include <iostream>
#include <queue>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 20

using namespace std;

// global variables
// 用来存储当前的变量
char *token_buffer;
char *head;        //保存公式指针
char *peek;        //当前位置
bool _neg;         //是否否定
char _name;        //节点名称
node *_hot;        //当前节点
volatile char *_var_string; //谓词对应的变量列表
char _var;         //单个变量
//以上变量将会在顺序读取时进行修改，全局共享

enum error_type
{
    UNRECG,   //不可识别
    NULLNODE, //空节点
    BADFMT    //格式错误
};

enum token
{              //供eat()使用
    LBRANK,    //左括号
    RBRANK,    //右括号
    PREDICATE, //谓词（变量会一起读取）
    QUANTITY,  //量词
    CONJKTION, //连接词
    END,       //读取完成
    UNRECGNZ,  //未知字符
    ERROR      //错误字符
};

void error(int type)
{ //错误提示信息
    switch (type)
    {
    case NULLNODE: //空节点
        printf("Cannot spary from a null node!");
        throw peek;
    case UNRECGNZ: //无法识别
        printf("Cannot recognize symbol at index %d ", peek - head);
        throw peek;
    case BADFMT: //格式错误
        printf("Cannot recognize format at index %d ", peek - head);
        throw peek;
    }
}
void erase_space_tab(string &s)
{
    int index = 0;
    if (!s.empty())
    {
        while ((index = s.find(' ', index)) != string::npos)
        {
            s.erase(index, 1);
        }
        index = 0;
        while ((index = s.find('\t', index)) != string::npos)
        {
            s.erase(index, 1);
        }
    }
}
token eat()
{ //将peek指针向前推移
    // 同时修改token_buffer
    char c = *peek;
    if (c == '\0')
    {
        peek++;
        return END;
    }
    if (c == ')')
    {
        peek++;
        return RBRANK; //右括号
    }
    if (c == '(')
    {
        if (*(peek + 1) == '@' | *(peek + 1) == '#')
        {
            // 量词
            // ->(@x)
            // 指针向前移动
            _neg = false;
            _name = *(peek + 1); //获取字母
            _var = *(peek + 2);
            peek += 4;
            return QUANTITY;
        }
        else
        {
            // TODO
            // 有没有错误检测
            peek++;
            return LBRANK; //左括号
        }
    }
    if (c == '!' || c == '%' || c == '>')
    {           //连接词
        peek++; //跳过连接符
        _name = c;
        return CONJKTION;
    }
    if (c > 'A' && c < 'Z')
    { //谓词
        // P(x,y,z)!()
        // P(x)!
        // 注册字母
        _name = c;
        _neg = false;
        // 跳到第一个变量
        peek += 2;
        string vs;
        if (*(peek - 1) == '(' && islower(*(peek)))
        {                    //左括号和字母
            vs = vs + *peek; //添加第一个字符
        }
        else
        {
            error(BADFMT);
            return ERROR;
        }
        while (*(peek + 1) == ',')
        {              //是一个逗号
            peek += 2; //跳过逗号
            if (islower(*peek))
            { //是一个小写字母
                vs = vs + *peek;
            }
            else
            {
                // 格式错误
                error(BADFMT);
                return ERROR;
            }
            // 现在peek的位置是一个小写字母
        }
        // 退出,peek相当于在z的位置
        if (*(peek + 1) == ')')
        {
            peek += 2;
        }
        // peek已经移出括号
        _var_string = (char *)vs.data();

        return PREDICATE;
    }
    error(UNRECG);
    return UNRECGNZ;
}

char *flush_buffer()
{
    //清空缓冲区
    delete[] token_buffer;
    token_buffer = new char[BUFFER_SIZE];
    return token_buffer;
}

node *spray(node *current, char *ss)
{ //从当前节点开始生长
    if (current == NULL)
    { //空节点
        error(NULLNODE);
    }
    peek = ss;
    head = peek;
    _hot = current;
    while (true)
    { //不断循环
        switch (eat())
        {                              //根据缓冲区内的内容，如果是
        case LBRANK:                   //左括号
            _hot = _hot->descend_lc(); //产生左子节点
            break;
        case CONJKTION: //连接词
            if (!_hot->to_conj(_name))
            { //如果为真则已经完成转换
                //返回空值代表该节点已经被定义
                // 格式错误
                error(BADFMT);
            }
            _hot = _hot->descend_rc(); //创建右节点
            break;
        case PREDICATE: //谓词
            if (!_hot->to_prid(_neg, _name, _var_string))
            {
                //返回空值代表该节点已经被定义
                error(BADFMT);
            }
            _hot = _hot->ascend(); //上溯
            break;
        case QUANTITY: //量词
            _hot->to_quant(_name, _var);
            _hot = _hot->descend_lc(); //创建空子节点
            break;
        case RBRANK:               //右括号
            _hot = _hot->ascend(); //上溯至父节点
            break;
        case END: //直至停止
        default:
            break;
        }
    }
}
void show(node *n)
{
    if (n->_sym)
    {
        printf(" %c", n->_sym);
    }
    else
    {
        printf(" [null]");
    }
}
void hierarchical_traverse(node *root, void (*visit)(node *))
{ //层序遍历
    queue<node *> q;
    node *cur;
    q.push(root);
    while (q.front())
    {
        cur = q.front();
        visit(cur);
        q.pop();
        if (cur->_lc) //左孩子非空
            q.push(cur->_lc);
        if (cur->_rc)
            q.push(cur->_rc);
    }
}

void neg_perculate_down(node *root)
{ //否定下滤，实际上采用层序遍历
    // 每一次都处理子节点
    // 之后将子节点加入队列中等待下滤
    //TODO
}